﻿/*
Copyright (c) 2009 Vratislav Cermak (vratacermak@gmail.com)
 
This file is part of TeachMe Project. See http://code.google.com/p/teach-me for more information.
 
TeachMe is an open source project. Using of TeachMe is free of charge.
It is distributed under GNU General Public License version 3 (GPLv3).
GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
 
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

using System;

namespace TeachMe.Application.Configuration
{
    public abstract class Checkable
    {
        private sealed class Editor : IDisposable
        {
            private bool _disposed;
            private readonly Checkable _checkable;

            public Editor(Checkable checkable)
            {
                _checkable = checkable;
                
                _checkable.CheckOut();
            }

            private void Dispose(bool disposing)
            {
                if (!_disposed)
                {
                    if (disposing)
                    {
                        _checkable.CheckIn();
                    }

                    // unmanaged resources

                    _disposed = true;
                }
            }

            public void Dispose()
            {
                Dispose(true);
            }
        }

        private int _checkOutCounter;
        private bool _saveIsNeeded;

        public event EventHandler<EventArgs> CheckedOut;
        public event EventHandler<EventArgs> Reverted;
        public event EventHandler<EventArgs> CheckedIn;

        public void CheckOut()
        {
            _checkOutCounter++;

            Fire(CheckedOut);
        }

        public void Revert()
        {
            Fire(Reverted);

            _checkOutCounter--;

            if (_checkOutCounter == 0 && _saveIsNeeded)
            {
                _saveIsNeeded = false;

                Save();
            }
        }

        public void CheckIn(bool leaveCheckedOut)
        {
            CheckIn();

            if (leaveCheckedOut)
            {
                CheckOut();
            }
        }

        public void CheckIn()
        {
            Fire(CheckedIn);

            _saveIsNeeded = true;
            
            if (_checkOutCounter == 0)
            {
                throw new InvalidOperationException();
            }
            _checkOutCounter--;
            

            if (_checkOutCounter == 0 && _saveIsNeeded)
            {
                _saveIsNeeded = false;

                Save();
            }
        }

        private void Fire(EventHandler<EventArgs> handler)
        {
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        public bool IsCheckedOut()
        {
            return _checkOutCounter > 0;
        }

        protected abstract void Save();

        public IDisposable Edit()
        {
            return new Editor(this);
        }
    }
}
